																																																																																																																																																																																																																																																																																																																																																																																	//           modelica-grammar.cpp
//  Sat Mar 14 21:49:22 2009
//  Copyright  2009  Jorge Eduardo Cardona Gaviria
//  <jorgeecardona@gmail.com>

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Library General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA

#include "modelica-grammar.hpp"

template <typename Iterator>
ModelicaGrammar<Iterator>::ModelicaGrammar() : ModelicaGrammar::base_type(stored_definition)
{
 
	
	// Reserved Keywords
    K_ALGORITHM = lit("algorithm"); 
    K_AND = lit("and");
    K_ANNOTATION = lit("annotation");
    K_ASSERT = lit("assert");
    K_BLOCK = lit("block");
    K_BREAK = lit("break");
    K_CLASS = lit("class");
    K_CONNECT = lit("connect");
    K_CONNECTOR = lit("connector");
    K_CONSTANT = lit("constant");
    K_CONSTRAINEDBY = lit("constrainedby");
    K_DER = lit("der");
    K_DISCRETE = lit("discrete");
    K_EACH = lit("each");
    K_ELSE = lit("else");
    K_ELSEIF = lit("elseif");
    K_ELSEWHEN = lit("elsewhen");
    K_ENCAPSULATED = lit("encapsulated");
    K_END = lit("end");	
    K_ENUMERATION = lit("enumeration");
    K_EQUATION = lit("equation");
    K_EXPANDABLE = lit("expandable");
    K_EXTENDS = lit("extends");
    K_EXTERNAL = lit("external");
    K_FALSE = lit("false");
    K_FINAL = lit("final");
    K_FLOW = lit("flow");
    K_FOR = lit("for");
    K_FUNCTION = lit("function");
    K_IMPORT = lit("import");
    K_IF = lit("if");
    K_IN = lit("in");
    K_INITIAL = lit("initial");
    K_INNER = lit("inner");
    K_INPUT = lit("input");
    K_LOOP = lit("loop");
    K_MODEL = lit("model");
    K_NOT = lit("not");
    K_OR = lit("or");
    K_OUTER = lit("outer");
    K_OUTPUT = lit("output");
    K_PACKAGE = lit("package");
    K_PARAMETER = lit("parameter");
    K_PARTIAL = lit("partial");
    K_PROTECTED = lit("protected");
    K_PUBLIC = lit("public");
    K_RECORD = lit("record");
    K_REDECLARE = lit("redeclare");
    K_REPLACEABLE = lit("replaceable");
    K_RETURN = lit("return");
    K_THEN = lit("then");
    K_TRUE = lit("true");
    K_TYPE = lit("type");
    K_WHEN = lit("when");
    K_WHILE = lit("while");
    K_WITHIN = lit("within");

	KEYWORDS_TABLE.add("algorithm",0);
	KEYWORDS_TABLE.add("and",0);
	KEYWORDS_TABLE.add("annotation",0);
	KEYWORDS_TABLE.add("assert",0);
	KEYWORDS_TABLE.add("block",0);
	KEYWORDS_TABLE.add("break",0);
	KEYWORDS_TABLE.add("class",0);
	KEYWORDS_TABLE.add("connect",0);
	KEYWORDS_TABLE.add("connector",0);
	KEYWORDS_TABLE.add("constant",0);
	KEYWORDS_TABLE.add("constrainedby",0);
	KEYWORDS_TABLE.add("der",0);
	KEYWORDS_TABLE.add("discrete",0);
	KEYWORDS_TABLE.add("each",0);
	KEYWORDS_TABLE.add("else",0);
	KEYWORDS_TABLE.add("elseif",0);
	KEYWORDS_TABLE.add("elsewhen",0);
	KEYWORDS_TABLE.add("encapsulated",0);
	KEYWORDS_TABLE.add("end",0);
	KEYWORDS_TABLE.add("enumeration",0);
	KEYWORDS_TABLE.add("equation",0);
	KEYWORDS_TABLE.add("expandable",0);
	KEYWORDS_TABLE.add("extends",0);
	KEYWORDS_TABLE.add("external",0);
	KEYWORDS_TABLE.add("false",0);
	KEYWORDS_TABLE.add("final",0);
	KEYWORDS_TABLE.add("flow",0);
	KEYWORDS_TABLE.add("for",0);
	KEYWORDS_TABLE.add("function",0);
	KEYWORDS_TABLE.add("import",0);
	KEYWORDS_TABLE.add("if",0);
	KEYWORDS_TABLE.add("in",0);
	KEYWORDS_TABLE.add("initial",0);
	KEYWORDS_TABLE.add("inner",0);
	KEYWORDS_TABLE.add("input",0);
	KEYWORDS_TABLE.add("loop",0);
	KEYWORDS_TABLE.add("model",0);
	KEYWORDS_TABLE.add("not",0);
	KEYWORDS_TABLE.add("or",0);
	KEYWORDS_TABLE.add("outer",0);
	KEYWORDS_TABLE.add("output",0);
	KEYWORDS_TABLE.add("package",0);
	KEYWORDS_TABLE.add("parameter",0);
	KEYWORDS_TABLE.add("partial",0);
	KEYWORDS_TABLE.add("protected",0);
	KEYWORDS_TABLE.add("public",0);
	KEYWORDS_TABLE.add("record",0);
	KEYWORDS_TABLE.add("redeclare",0);
	KEYWORDS_TABLE.add("replaceable",0);
	KEYWORDS_TABLE.add("return",0);
	KEYWORDS_TABLE.add("then",0);
	KEYWORDS_TABLE.add("true",0);
	KEYWORDS_TABLE.add("type",0);
	KEYWORDS_TABLE.add("when",0);
	KEYWORDS_TABLE.add("while",0);
	KEYWORDS_TABLE.add("within",0);

	KEYWORDS			= lexeme[KEYWORDS_TABLE >> !(NONDIGIT|DIGIT)];
	
	NONDIGIT			= char_("_") | char_("a-z") | char_("A-Z");
 	DIGIT				= char_("0-9");
    IDENT               %= raw[(lexeme[NONDIGIT >> *(NONDIGIT | DIGIT)] | Q_IDENT) - KEYWORDS];
    UNSIGNED_INTEGER    = lexeme[DIGIT >> *DIGIT];
    UNSIGNED_NUMBER     = UNSIGNED_INTEGER >> -(char_(".") >> -UNSIGNED_INTEGER ) >> -((char_("e")|char_("E")) >> -(char_("+") | char_("-")) >> UNSIGNED_INTEGER);
    STRING              = char_("\"") >> *(S_CHAR | S_ESCAPE) >> char_("\"");
    S_CHAR              = char_ - (char_("\\")|char_("\""));
    Q_CHAR              = char_ - (char_("\\")|char_("'"));
    S_ESCAPE            = (lit("\\'") | lit("\\\"") | lit("\\?") | lit("\\\\") | 
                           lit("\\a") | lit("\\b")  | lit("\\f") | lit("\\n")  | lit("\\r") | lit("\\t") | lit("\\v"));
    Q_IDENT             = char_("'") >> (Q_CHAR | S_ESCAPE) >> *(Q_CHAR | S_ESCAPE) >> char_("'");

    name                = IDENT >> -(char_('.') >> IDENT);
	
    // Appendix B.2.1 Stored Definitions - Within.
    stored_definition	   = (-(K_WITHIN >> -(name[phoenix::at_c<0>(_val) = _1]) >> ";") >> 
		                    *(-K_FINAL >> class_definition[phoenix::push_back(phoenix::at_c<1>(_val), _1)] >> ";"));

	class_definition		=   -(K_ENCAPSULATED[_a = true]) >> 
								-(K_PARTIAL [_b = true]) >> 
				        		(   K_CLASS			[_val = phoenix::new_<Modelica::Class>(_a, _b)]		| 
									K_MODEL			[_val = phoenix::new_<Modelica::Model>(_a, _b)]		| 
									K_RECORD		[_val = phoenix::new_<Modelica::Record>(_a, _b)]	| 
									K_BLOCK			[_val = phoenix::new_<Modelica::Block>(_a, _b)]		| 
									(   -K_EXPANDABLE[_c = true] >> 
										K_CONNECTOR [_val = phoenix::new_<Modelica::Connector>(_a, _b, _c)]
									) |
									K_TYPE			[_val = phoenix::new_<Modelica::Type>(_a, _b)]		| 
									K_PACKAGE		[_val = phoenix::new_<Modelica::Package>(_a, _b)]	| 
									K_FUNCTION		[_val = phoenix::new_<Modelica::Function>(_a, _b)]
								) >> class_specifier(_val);

	
	class_specifier			=   ( /*Normal specification of a class.*/
									IDENT[bind(&Modelica::Class::name, _r1) = _1] >> 
									string_comment[bind(&Modelica::Class::comment, _r1) = _1] >> 
									composition(_r1) >> 
									K_END >> lit(_r1->*&Modelica::Class::name))
				          		| /**/
									(IDENT >> char_("=") >> base_prefix >> name
				            		>> -array_subscripts /*>> -class_modification*/ >> comment)
				                | /**/
									(IDENT >> char_("=") >> K_ENUMERATION >> char_("(") 
				                		/*>> ((-enum_list) | char_(":"))*/ >> char_(")") >> comment)
				                    | (IDENT >> char_("=") >> K_DER >> char_("(") >> name 
				                		>> char_(",") >> IDENT >> *(char_(",") >> IDENT) 
				                		>> char_(")") >> comment)
				                    | (K_EXTENDS >> IDENT /*>> -class_modification*/ >> string_comment 
				                		/*>> composition*/ >> K_END >> IDENT);
	
    base_prefix             = eps >> type_prefix;

    enum_list               = enumeration_literal >> *(char_(",") >> enumeration_literal);

    enumeration_literal     = IDENT >> comment;

    composition             = /*(*/element_list(_r1, false) >>
                        		*(  (K_PUBLIC >> element_list(_r1, false)) |
                          			(K_PROTECTED >> element_list(_r1, true))
                          			/*|equation_section
                          			|algorithm_section*/
                        		) /*>> -(K_EXTERNAL >> -language_specification >> -external_function_call >> -annotation >> char_(";") >> -(annotation >> char_(";"))))*/; 

    language_specification  = eps >> STRING;
/*
    external_function_call  = -(component_reference >> char_("=")) >> IDENT >> char_("(") >> -expression_list >> char_(")");
*/
    element_list            = *((   element[bind(&Modelica::Element::is_protected, _1) = _r2, 
										 phoenix::push_back(bind(&Modelica::Class::elements, _r1), _1)] | 
									annotation) >> char_(";"));

    element                 = /*(import_clause
                            | extends_clause
                            | ( */
							  	-(K_REDECLARE[_a=true]) >> 
                                -K_FINAL[_b=true] >> 
                                -K_INNER[_c=true] >>
								-K_OUTER[_d=true] >> 
                                (   (class_definition | 
									 component_clause(_a,_b,_c,_d,false)[_val=_1])|
									(K_REPLACEABLE >> ( class_definition | 
														component_clause(_a,_b,_c,_d,true)[_val=_1])
										>> -(constraining_clause >> comment)))/*))*/;

    import_clause           = K_IMPORT >> ((IDENT >> char_("=") >> name) | (name >> -(char_(".") >> char_("*")))) >> comment;

    // Appendix B.2.3 Extends
    
    extends_clause      = K_EXTENDS >> name /*>> -class_modification */>> -annotation;

    constraining_clause = K_CONSTRAINEDBY >> name /*>> -class_modification*/;

    // Appendix B.2.4 Component Clause

    component_clause        = eps[_val = phoenix::new_<Modelica::Component>(_r1,_r2,_r3,_r4,_r5)] >> 
								type_prefix >> 
								type_specifier /*>> -array_subscripts*/ >> component_list;

    type_prefix             =   -(K_FLOW/*[bind(&Modelica::Component::prefix, _r1) = construct<Modelica::Prefix>()]*/) >>
								-(  K_DISCRETE/*[bind(&Modelica::Prefix::discrete,_r1) = true]*/ | 
									K_PARAMETER/*[bind(&Modelica::Prefix::parameter,_r1) = true]*/ | 
									K_CONSTANT/*[bind(&Modelica::Prefix::constant,_r1) = true]*/) >> 
								-(  K_INPUT/*[bind(&Modelica::Prefix::input,_r1) = true]*/ | 
									K_OUTPUT/*[bind(&Modelica::Prefix::output,_r1) = true]*/);

    type_specifier          = eps >> name;

    component_list          = component_declaration >> *(char_(",") >> component_declaration);

    component_declaration   = eps >> declaration /*>> -conditional_attribute >> comment*/;
/*
    conditional_attribute   = K_IF >> expression;
*/
    declaration             = eps >> IDENT /*>> -array_subscripts /*>> -modification*/;
/*
    // Appendix B.2.5 Modification

    modification                        = (class_modification >> -(char_("=") >> expression))
                                        | (char_("=") >> expression)
                                        | (lit(":=") >> expression);

    class_modification                  = char_("(") >> -argument_list >> char_(")");

    argument_list                       = argument >> *(char_(",") >> argument);

    argument                            = element_modification_or_replaceable | element_redeclaration;

    element_modification_or_replaceable = -K_EACH >> -K_FINAL >> (element_modification | element_replaceable);

    element_modification                = component_reference >> -modification >> string_comment;

    element_redeclaration               = K_REDECLARE >> -K_EACH >> -K_FINAL >> ((class_definition | component_clause1) | element_replaceable);

    element_replaceable                 = K_REPLACEABLE >> (class_definition | component_clause1) >> -constraining_clause;

    component_clause1                   = type_prefix >> type_specifier >> component_declaration1;

    component_declaration1              = declaration >> comment;

    // Appendix B.2.6 Equations
    
    equation_section    = -K_INITIAL >> K_EQUATION >> *((equation | annotation) >> char_(";"));

    algorithm_section   = -K_INITIAL >> K_ALGORITHM >> *((statement | annotation) >> char_(";"));
    
    equation            = (  (simple_expression >> char_("=") >> expression)
                            | if_equation
                            | for_equation
                            | connect_clause
                            | when_equation
                            | ((K_DER | K_ASSERT | IDENT) >> function_call_args)) >> comment;

    statement           = (  (component_reference >> ((lit(":=") >> expression) | function_call_args))
                            |(char_("(") >> output_expression_list >> char_(")") >> lit(":=") >> component_reference >> function_call_args)
                            | K_BREAK
                            | K_RETURN
                            | if_statement
                            | for_statement
                            | while_statement
                            | when_statement ) >> comment;

    if_equation         = K_IF >> expression >> K_THEN >>
                            *(equation >> char_(";")) >>
                        *(K_ELSEIF >> expression >> K_THEN >>
                            *(equation >> char_(";"))) >>
                        -(K_ELSE >>
                            *(equation >> char_(";"))) >>
                        K_END >> K_IF;

    if_statement        = K_IF >> expression >> K_THEN >>
                            *(statement >> char_(";")) >>
                        *(K_ELSEIF >> expression >> K_THEN >>
                            *(statement >> char_(";"))) >>
                        -(K_ELSE >>
                            *(statement >> char_(";"))) >>
                        K_END >> K_IF;

    for_equation        = K_FOR >> for_indices >> K_LOOP >>
                            *(equation >> char_(";")) >>
                        K_END >> K_FOR;

    for_statement       = K_FOR >> for_indices >> K_LOOP >>
                            *(statement >> char_(";")) >>
                        K_END >> K_FOR;

    for_indices         = for_index >> *(char_(";") >> for_index);

    for_index           = IDENT >> -(K_IN >> expression);

    while_statement     = K_WHILE >> expression >> K_LOOP >>
                            *(statement >> char_(";")) >>
                        K_END >> K_WHILE;

    when_equation       = K_WHEN >> expression >> K_THEN >>
                            *(equation >> char_(";")) >>
                        *(K_ELSEWHEN >> expression >> K_THEN >>
                            *(equation >> char_(";"))) >>
                        K_END >> K_WHEN;

    when_statement      = K_WHEN >> expression >> K_THEN >>
                            *(statement >> char_(";")) >>
                        *(K_ELSEWHEN >> expression >> K_THEN >>
                            *(statement >> char_(";"))) >>
                        K_END >> K_WHEN;

    connect_clause      = K_CONNECT >> char_("(") >> component_reference >> char_(",") >> component_reference >> char_(")");


    // Appendix B.2.7 Exprssions
    
    expression              = simple_expression 
                            | (K_IF >> expression >> K_THEN >> expression >> *(K_ELSEIF >> expression >> K_THEN >> expression) >> 
                            K_ELSE >> expression );

    simple_expression       = logical_expression >> -(char_(":") >> logical_expression >> -(char_(":") >> logical_expression));

    logical_expression      = logical_term >> *(K_OR >> logical_term);
    
    logical_term            = logical_factor >> *(K_AND >> logical_factor);

    logical_factor          = -K_NOT >> relation;

    relation                = arithmetic_expression >> -(rel_op >> arithmetic_expression);
*/
    rel_op                  = lit("<>") | lit("<=") | char_("<") | lit(">=") | char_(">") | lit("==");
/*
    arithmetic_expression   = -add_op >> term >> *(add_op >> term);
*/
    add_op                  = char_("+") | char_("-") | lit(".+") | lit(".-");
/*
    term                    = factor >> *(mul_op >> factor);
*/
    mul_op                  = char_("*") | char_("/") | lit(".*") | lit("./");
/*
    factor                  = primary >> -((char_("^") | lit(".^")) >> primary);

    primary                 = UNSIGNED_NUMBER
                            | STRING
                            | K_FALSE
                            | K_TRUE
                            | ((K_DER | K_ASSERT | name) >> function_call_args)
                            | component_reference
                            | (char_("(") >> output_expression_list >> char_(")"))
                            | (char_("[") >> expression_list >> *(char_(";") >> expression_list) >> char_("]"))
                            | (char_("{") >> function_arguments >> char_("}"))
                            | K_END;
*/
    name                    %= raw[IDENT >> -(char_(".") >> name)];
/*
    component_reference     = IDENT >> -array_subscripts >> -(char_(".") >> component_reference);

    function_call_args      = char_("(") >> -function_arguments >> char_(")");

    function_arguments      = named_arguments | (expression >> -((char_(",") >> function_arguments) | (K_FOR >> for_indices)));

    named_arguments         = named_argument >> -(char_(",") >> named_arguments);

    named_argument          = IDENT >> char_("=") >> expression;

    output_expression_list  = -expression >> *(char_(",") >> expression);

    expression_list         = expression >> *(char_(",") >> expression);
*/
    array_subscripts        = char_("[") >> subscript >> *(char_(",") >> subscript) >> char_("]");

    subscript               = eps >> char_(":") /*| expression*/;

    comment                 = eps >> string_comment >> -annotation;

    string_comment          %= raw[-(STRING >> *( char_("+") >> STRING))];

    annotation              = eps >> K_ANNOTATION /*>> class_modification*/;


}



Modelica::Stored read_string(string content)
{
	// Start parser
	ModelicaGrammar<std::string::const_iterator> modelica;

    std::string::const_iterator start = content.begin();
    std::string::const_iterator iter = content.begin();
    std::string::const_iterator end = content.end();
	
	Modelica::Stored s;
	
	bool r = phrase_parse(iter, end, modelica, s, space);
	
//	std::cout  << "Leido:\n" << string(start, iter) << "<<<\n";
	
//	std::cout << "Within: " << s.within << std::endl;
//	std::cout << "Classes No.: " << s.classes.size() << std::endl;
	
	for( int i=0; i< s.classes.size(); i++)
	{
		cout << " Name: " << s.classes[i]->name << endl;
	}
	
	return s;																		
}



